/*
 * Copyright (c) 2018 Hitevision
 */

package tw.com.hitevision.whiteboard.android.display;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.graphics.Color;
import android.net.Uri;
import android.provider.Settings;
import android.util.Log;

import com.mstar.android.tv.TvPictureManager;
import com.mstar.android.tvapi.common.TvManager;
import com.mstar.android.tvapi.common.exception.TvCommonException;

import androidx.annotation.ColorInt;
import androidx.core.graphics.ColorUtils;

import tw.com.hitevision.whiteboard.android.Props;
import tw.com.hitevision.whiteboard.android.util.ContentProviderUtils;

public class DisplayManagerImpl implements DisplayManager {
    private static final String TAG = DisplayManager.class.getSimpleName();

    private static final Uri SETTINGS_CONTENT_URI = Uri.parse("content://mstar.hv.usersetting/functionsetting");

    private TvManager manager;
    private TvPictureManager pictureManager;
    private boolean isSupported;

    DisplayManagerImpl() {
        if (!Props.getFlavorChipset().equals(Props.Flavor.Chipset.Mstar)
                && !Props.getFlavorChipset().equals(Props.Flavor.Chipset.Optoma)) {
            isSupported = false;
            return;
        }

        try {
            manager = TvManager.getInstance();
        } catch (UnsatisfiedLinkError e) {
            e.printStackTrace();
        }

        try {
            pictureManager = TvPictureManager.getInstance();
        } catch (UnsatisfiedLinkError e) {
            e.printStackTrace();
        }

        isSupported = true;
    }

    /**
     * Checks system settings and returns {@code true} if writing eye protection mode is enabled.
     */
    @Override
    public boolean isWritingEyeProtectionEnabled(Context context) {
        if (!isSupported) {
            return false;
        }

        if (Props.getMainboardVersion() == Props.Mainboard.V_848) {
            final int openEyeWriteMode = ContentProviderUtils
                    .queryInteger(context, SETTINGS_CONTENT_URI, "bWriteProtection");
            return openEyeWriteMode == 1;
        } else {
            if (manager != null && pictureManager != null) {
                try {
                    return "1".equals(manager.ReadCmdFromTVOS("GetEyeWritemode"));
                } catch (TvCommonException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    @Override
    public boolean isBluelightFilterEnabled(Context context) {
        if (!isSupported) {
            return false;
        }

        return ContentProviderUtils.queryInteger(context, SETTINGS_CONTENT_URI,
                "bEnableBlueLightFilter") == 1;
    }

    @Override
    public int getBluelightFilterValue(Context context) {
        if (!isSupported) {
            return 0;
        }

        return ContentProviderUtils.queryInteger(context, SETTINGS_CONTENT_URI,
                "nBlueLightFilterValue");
    }

    @Override
    @ColorInt
    public int getBluelightFilteredColor(Context context, @ColorInt int color) {
        if (!isSupported) {
            return 0;
        }

        log("getBluelightFilteredColor: color=" + color);
        final int filterValue = getBluelightFilterValue(context);
        final int overlayColor = getBluelightFilterOverlayColor(filterValue);

        return ColorUtils.compositeColors(overlayColor, color);
    }

    private int getBluelightFilterOverlayColor(int filterValue) {
        // overlay color algorithm is taken from BlueLightService.kt
        final float alphaF;
        if (filterValue < 20) {
            alphaF = 0.22f * filterValue / 20;
        } else {
            alphaF = 0.22f + 0.03f * (filterValue - 20) / 30;
        }
        final int a = (int) (alphaF * 255);

        final int factor = Math.min((int) (filterValue * 0.8f), 80);
        final int r = (int) (95 + factor / 80f * 130);
        final int g = (int) (50 + factor / 80f * 115);
        final int b = (int) (120 - factor / 80f * 120);

        return Color.argb(a, r, g, b);
    }

    /**
     * Sets the display backlight.
     */
    @Override
    public void setBacklight(Context context, int value) {
        if (!isSupported) {
            return;
        }

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Xvn)) {
            if (pictureManager != null) {
                try {
                    pictureManager.setBacklight(value);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } else {
            try {
                Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, value);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * This method is required as a workaround for TvPictureManager not updating the backlight
     * value correctly.
     */
    @Override
    public void saveBacklightToSettings(Context context, int value) {
        if (!isSupported) {
            return;
        }

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Xvn)) {
            final ContentResolver resolver = context.getContentResolver();

            final ContentValues brightness = new ContentValues();
            brightness.put("u8Backlight", value);

            for (int i = 0; i < 9; i++) {
                resolver.update(Uri.parse("content://mstar.tv.usersetting/picmode_setting/inputsrc/34/picmode/" + i), brightness, null, null);
                resolver.update(Uri.parse("content://mstar.tv.usersetting/picmode_setting/inputsrc/23/picmode/" + i), brightness, null, null);
                resolver.update(Uri.parse("content://mstar.tv.usersetting/picmode_setting/inputsrc/24/picmode/" + i), brightness, null, null);
                resolver.update(Uri.parse("content://mstar.tv.usersetting/picmode_setting/inputsrc/25/picmode/" + i), brightness, null, null);
                resolver.update(Uri.parse("content://mstar.tv.usersetting/picmode_setting/inputsrc/0/picmode/" + i), brightness, null, null);
            }
        }
    }

    /**
     * Returns the current backlight value.
     *
     * @return the backlight value, {@code 0} if unsupported
     */
    @Override
    public int getBacklight(Context context) {
        log("getBacklight");
        if (Props.getFlavorModel().equals(Props.Flavor.Model.Xvn)) {
            if (pictureManager != null) {
                try {
                    return pictureManager.getBacklight();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return 0;
        } else {
            int value;
            try {
                value = Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
            } catch (Settings.SettingNotFoundException e) {
                value = 0;
                e.printStackTrace();
            }
            log("- value=" + value);

            if (value > 100 && Props.getMainboardVersion() == Props.Mainboard.V_828) {
                // cap value at 100
                log("- capping value to 100");
                value = 100;
            }
            return value;
        }
    }

    private static void log(String msg) {
        Log.d(TAG, msg);
    }
}
